unit uMesh;

interface

uses
  System.Classes,
  System.SysUtils,
  Vcl.Dialogs,
  GLS.Objects,
  GLS.VectorTypes,
  GLS.VectorFileObjects,
  GLS.Scene,
  GLS.Color,
  GLS.VectorGeometry;



type
  TEffect = (effNone,effReflect,effReflect2,effAlphaChanelPNG);
  TMDTexture = record
    Name     : AnsiString;
    FileName : AnsiString;
    Scale    : TGLVector;
    Offset   : TGLVector;
    Enable   : Boolean;
  end;

  TMaterialData = record
    Name    : AnsiString;
    Texture : TMDTexture;
    Effect  : TEffect;
    Color   : TGLColor;
  end;


type
  TPosDirPoint = class
  public
    Name: AnsiString;
    Position: TGLVector;
    Direction: TGLVector;
    Up: TGLVector;
  end;

  TPosDirPointList = class
  public
  end;

  TTypeMesh = (tmStatic, tmDynamic);

  TBaseObject = class(TGLQuadricObject)
  public
    Geom: TGLCustomSceneObject;
    FName: AnsiString;
    Action: AnsiString;
    FileName: AnsiString;
    TypeMesh: TTypeMesh;
    MaterialData: TMaterialData;
  end;

  TMesh = class(TGLFreeForm)
  public
    // Geom         : TGLCustomSceneObject;
    FName: AnsiString;
    Action: AnsiString;
    FileName: AnsiString;
    TypeMesh: TTypeMesh;
    MaterialData: TMaterialData;
  end;

  TAnimatedMesh = class(TBaseObject)
  public
    Geom: TGLActor;
    constructor Create(AOwner: TComponent); override;
  end;

  TMeshItem = record
    Name: AnsiString;
    FName: AnsiString;
    FileName: AnsiString;
    TypeMesh: TTypeMesh;
    Animation: Boolean;
  end;

  TMeshList = class
  public
    Items: array of TMeshItem;
    Count: Integer;

    constructor Create;

    function GetItemByName(iName: AnsiString): TMeshItem;
    function AddItem(iFileName: AnsiString; iTypeMesh: TTypeMesh;
      iAnimation: Boolean): TMeshItem; overload;
    function AddItem: TMeshItem; overload;
    procedure SaveList(FileName: AnsiString);
    procedure LoadList(FileName: AnsiString);
    procedure ClearList;
  end;


type
  TMap = class(TMesh)
  public
    Title: AnsiString;
    PathFile: AnsiString;
    //
    MeshList: TMeshList;
    ObjList: TList;
    GLScene: TGLScene;
    c: Integer;

    procedure Load(FileName: AnsiString);
    procedure Build;
    procedure Clear;
    function AddMesh(Name, FileName: AnsiString): TMesh;
    procedure Init;
  end;

//====================================================================
implementation

uses
  uMaterials,
  uUtils;


// * TStaticMesh *//


// * TMeshItem *//

function TMeshList.AddItem(iFileName: AnsiString; iTypeMesh: TTypeMesh;
  iAnimation: Boolean): TMeshItem;
begin
  SetLength(Items, Count + 1);

  Items[Count].Name := 'Mesh_' + IntToStr(Count);
  Items[Count].FName := Items[Count].Name + ExtractFileExt(iFileName);
  Items[Count].FileName := iFileName;
  Items[Count].TypeMesh := iTypeMesh;
  Items[Count].Animation := iAnimation;

  Result := Items[Count];

  Count := Count + 1;
end;

function TMeshList.AddItem: TMeshItem;
begin
  SetLength(Items, Count + 1);

  Items[Count].Name := 'Mesh_' + IntToStr(Count);
  Items[Count].FName := Items[Count].Name;
  Items[Count].FileName := '';
  Items[Count].TypeMesh := tmStatic;
  Items[Count].Animation := False;

  Result := Items[Count];
  Count := Count + 1;
end;

constructor TMeshList.Create;
begin
  Count := 0;
end;

function TMeshList.GetItemByName(iName: AnsiString): TMeshItem;
var
  i: Integer;
begin
  if Count <> 0 then
    for i := 0 to Count - 1 do
      if Items[i].Name = iName then
      begin
        Result := Items[i];
        Exit;
      end;
end;

procedure TMeshList.SaveList(FileName: AnsiString);
var
  i: Integer;
  F: TextFile;
begin
  AssignFile(F, FileName);
  Rewrite(F);

  for i := 0 to Count - 1 do
  begin
    WriteLn(F, Items[i].Name);
    WriteLn(F, Items[i].FName);

    case Items[i].TypeMesh of
      tmStatic:
        WriteLn(F, '0');
      tmDynamic:
        WriteLn(F, '1');
    end;

    WriteLn(F, Items[i].Animation);
  end;
  CloseFile(F);
end;

procedure TMeshList.LoadList(FileName: AnsiString);
var
  F: TextFile;
  i: Integer;
  Dir: AnsiString;
  Tag: AnsiString;
  MeshItem: TMeshItem;
begin
  ClearList;
  Dir := ExtractFileDir(FileName) + '\';

  AssignFile(F, FileName);
  Reset(F);

  while not EOF(F) do
  begin
    MeshItem := AddItem;
    with MeshItem do
    begin
      ReadLn(F, Name);
      ReadLn(F, FName);
      ReadLn(F, i);
      case i of
        0:
          TypeMesh := tmStatic;
        1:
          TypeMesh := tmDynamic;
      end;
      ReadLn(F, Tag);
      if Tag = 'TRUE' then
        Animation := True
      else
        Animation := False;

      FileName := Dir + FName;
    end;

    Items[Count - 1] := MeshItem;
  end;
  CloseFile(F);
end;

procedure TMeshList.ClearList;
begin
  SetLength(Items, 0);
  Count := 0;
end;

// * TAnimatedMesh *//

constructor TAnimatedMesh.Create(AOwner: TComponent);
begin
  inherited;
  Geom := TGLActor(AddNewChild(TGLActor));
end;


// * TMap *//

procedure TMap.Init;
begin
  ObjList := TList.Create;
  MeshList := TMeshList.Create;
end;

procedure TMap.Load(FileName: AnsiString);
var
  F: TextFile;
  N: Single;
  S1, S2: AnsiString;
  TmpList: TStringList;
  S3, Dir: AnsiString;
  Mesh: TMesh;
  I: Integer;
begin
  Clear;

  c := 0;
  Title := ChangeFileExt(ExtractFileName(FileName), '');
  Dir := ExtractFileDir(FileName) + PathDelim + Title + '_dat' + PathDelim;

  MeshList.LoadList(Dir + 'Meshes.info');

  AssignFile(F, FileName);
  Reset(F);

  ReadLn(F, N); // Camera.Position.X := N;
  ReadLn(F, N); // Camera.Position.Y := N;
  ReadLn(F, N); // Camera.Position.Z := N;

  ReadLn(F, N); // Target.Position.X := N;
  ReadLn(F, N); // Target.Position.Y := N;
  ReadLn(F, N); // Target.Position.Z := N;

  while not EOF(F) do
  begin
    ReadLn(F, S1);
    ReadLn(F, S2);
    ReadLn(F, S3);

    if S1 = 'Mesh:' then
      Mesh := AddMesh(S2, S3);

    ReadLn(F, Mesh.Action);

    ReadLn(F, N);
    Mesh.Position.X := N;
    ReadLn(F, N);
    Mesh.Position.Y := N;
    ReadLn(F, N);
    Mesh.Position.Z := N;

    ReadLn(F, N);
    Mesh.Scale.X := N;
    ReadLn(F, N);
    Mesh.Scale.Y := N;
    ReadLn(F, N);
    Mesh.Scale.Z := N;

    ReadLn(F, N);
    Mesh.PitchAngle := N;
    ReadLn(F, N);
    Mesh.TurnAngle := N;
    ReadLn(F, N);
    Mesh.RollAngle := N;

    ReadLn(F);
    ReadLn(F);
    ReadLn(F);
    ReadLn(F, S1);

    Mesh.MaterialData.Texture.Name := S1;
    Mesh.MaterialData.Texture.FileName := Dir + S1;

    ReadLn(F, S1);

    if S1 = 'TRUE' then
      Mesh.MaterialData.Texture.Enable := True
    else
      Mesh.MaterialData.Texture.Enable := False;

    ReadLn(F, N);
    Mesh.MaterialData.Texture.Scale.X := N;
    ReadLn(F, N);
    Mesh.MaterialData.Texture.Scale.Y := N;
    ReadLn(F, N);
    Mesh.MaterialData.Texture.Scale.Z := N;

    ReadLn(F, N);
    Mesh.MaterialData.Texture.Offset.X := N;
    ReadLn(F, N);
    Mesh.MaterialData.Texture.Offset.Y := N;
    ReadLn(F, N);
    Mesh.MaterialData.Texture.Offset.Z := N;

    ReadLn(F, I);

    case I of
      0:
        Mesh.MaterialData.Effect := effNone;
      1:
        Mesh.MaterialData.Effect := effReflect;
      2:
        Mesh.MaterialData.Effect := effReflect2;
      3:
        Mesh.MaterialData.Effect := effAlphaChanelPNG;
    end;

    ReadLn(F, I);
    Mesh.MaterialData.Color.AsWinColor := I;
    ReadLn(F, N);
    Mesh.MaterialData.Color.Alpha := N;
    ApplyMaterialData(MaterialLibrary, Mesh);
  end;

  CloseFile(F);
end;

procedure TMap.Clear;
var
  I: Integer;
  Mesh: TMesh;
begin
  for I := 0 to ObjList.Count - 1 do
  begin
    Mesh := ObjList[I];
    FreeAndNil(Mesh);
  end;

  MeshList.ClearList;
  ObjList.Clear;
end;

function TMap.AddMesh(Name, FileName: AnsiString): TMesh;
var
  I, N: Integer;
  Mesh: TMesh;
  MeshItem: TMeshItem;
begin
  Result := nil;
  MeshItem := MeshList.GetItemByName(FileName);
  Mesh := TMesh(GLScene.Objects.AddNewChild(TMesh));
  Mesh.FName := MeshItem.Name;
  Mesh.FileName := MeshItem.FileName;
  Mesh.TypeMesh := MeshItem.TypeMesh;

  Mesh.Scale.SetVector(10, 10, 10);

  // if not MeshItem.Animation then
  // for i:= 0 to (Mesh as TMesh).Geom.MeshObjects.Count - 1 do
  // (Mesh as TMesh).Geom.MeshObjects[i].UseVBO:= False;

  // if not MeshItem.Animation then
  (Mesh as TMesh).LoadFromFile(Mesh.FileName);
  // else (Mesh as TAnimatedMesh).Geom.LoadFromFile(Mesh.FileName);

  Mesh.Name := Name;

  MaterialLibrary.Materials.Add.Name := 'Material' + IntToStr(MaterialLibrary.Materials.Count);
  N := MaterialLibrary.Materials.Count - 1;

  Mesh.MaterialData.Name := MaterialLibrary.Materials[N].Name;
  Mesh.MaterialData.Color := TGLColor.Create(nil);

  // if not MeshItem.Animation then
  // begin
  Mesh.Material.MaterialLibrary := MaterialLibrary;
  Mesh.Material.LibMaterialName := Mesh.MaterialData.Name;
  Mesh.MeshObjects.UseVBO := False;
  Mesh.BuildOctree(3);
  // Mesh.ObjectStyle:= [osDirectDraw];
  // end else
  // begin
  // (Mesh as TAnimatedMesh).Geom.Material.MaterialLibrary := MaterialLibrary;
  // (Mesh as TAnimatedMesh).Geom.Material.LibMaterialName := Mesh.MaterialData.Name;
  // end;

  ResetMaterialData(Mesh.MaterialData);
  ApplyMaterialData(MaterialLibrary, Mesh);

  ObjList.Add(Mesh);

  Result := Mesh;
end;

procedure TMap.Build;
var
  I: Integer;
  Obj: TMesh;
  mR: TGLMatrix;
begin
  MeshObjects.UseVBO := False;

  for I := 0 to ObjList.Count - 1 do
  begin
    Obj := ObjList[I];
    CopyMeshObj(Obj, Self, Obj.Matrix^);
    FreeAndNil(Obj)
  end;

  BuildOctree(3);
end;


end.
